﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//using System.Windows.Forms
using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.Platform.Windows;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private int[] points;
        private int[] solution;

        public Form1()
        {
            InitializeComponent();
            AnT.InitializeContexts();
        }

        public struct Pair
        {
            public int first;
            public int second;
        };

        private Thread hillClimbingThread_           = null;
        private Thread multistartHillClimbingThread_ = null;
        private Thread annealThread_                 = null;
        private Thread multistartAnnealThread_ = null;
        
        private void Form1_Load(object sender, EventArgs e)
        {
            Glut.glutInit();
            Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
            Gl.glClearColor(1, 1, 1, 1);
            Gl.glViewport(0, 0, AnT.Width, AnT.Height);

            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluPerspective(45, (float)AnT.Width / (float)AnT.Height, 0.1, 200);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Gl.glEnable(Gl.GL_DEPTH_TEST);

            timer1.Start();

            hillClimbingThread_ = new Thread(new ThreadStart(this.HillClimbingCallback));
            multistartHillClimbingThread_ = new Thread(new ThreadStart(this.MultistartHillClimbingCallback));
            annealThread_                 = new Thread(new ThreadStart(this.AnnealCallback));
            multistartAnnealThread_       = new Thread(new ThreadStart(this.MultistartAnnealCallback));
        }

        public int angleX = 0;
        public int angleY = 0;
        public int angleZ = 0;
        public float radius = 2.1f;
        public int[] solution_;
        TSP.DataFromFile data = new TSP.DataFromFile();

        public void DisplaySpheres()
        {
            Glu.GLUquadric q = new Glu.GLUquadric();
            
            const double sphereRadius = 0.2;
            for (int i = 0; i < solution_.Length; ++i)
            {
                double dx = 2.0 * radius * Math.Sin(i * Math.PI / (1.0 * solution_.Length)) * Math.Cos(Math.PI / 2 - i * Math.PI / (1.0 * solution_.Length));
                double dy = 2.0 * radius * Math.Sin(i * Math.PI / (1.0 * solution_.Length)) * Math.Sin(Math.PI / 2 - i * Math.PI / (1.0 * solution_.Length));
                Gl.glTranslated(dx - radius, dy, 0);
                Glut.glutSolidSphere(0.1, 20, 20);
                Gl.glRasterPos3d((dx - radius) / 9, dy / 9, 0);
                Glut.glutBitmapString(Glut.GLUT_BITMAP_HELVETICA_10, i.ToString());
                Gl.glTranslated(-dx + radius, -dy, 0);
            }
        }

        public void DisplayConnections()
        {
            for (int i = 0; i < solution_.Length - 1; ++i)
            {
                double dx1 = 2.0 * radius * Math.Sin(solution_[i] * Math.PI / (1.0 * solution_.Length)) * Math.Cos(Math.PI / 2 - solution_[i] * Math.PI / (1.0 * solution_.Length));
                double dy1 = 2.0 * radius * Math.Sin(solution_[i] * Math.PI / (1.0 * solution_.Length)) * Math.Sin(Math.PI / 2 - solution_[i] * Math.PI / (1.0 * solution_.Length));

                double dx2 = 2.0 * radius * Math.Sin(solution_[i + 1] * Math.PI / (1.0 * solution_.Length)) * Math.Cos(Math.PI / 2 - solution_[i + 1] * Math.PI / (1.0 * solution_.Length));
                double dy2 = 2.0 * radius * Math.Sin(solution_[i + 1] * Math.PI / (1.0 * solution_.Length)) * Math.Sin(Math.PI / 2 - solution_[i + 1] * Math.PI / (1.0 * solution_.Length));

                Gl.glBegin(Gl.GL_LINES);
                Gl.glVertex3d(dx1 - radius, dy1, 0);
                Gl.glVertex3d(dx2 - radius, dy2, 0);
                Gl.glEnd();
            }

        }

        public void Draw(int timeout)
        {
            Thread.Sleep(timeout);
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);

            Gl.glLoadIdentity();
            Gl.glColor3f(1.0f, 0, 0);

            Gl.glPushMatrix();

            Gl.glTranslated(0, 0, -6);
            Gl.glRotated(angleX, 1, 0, 0);
            Gl.glRotated(angleY, 0, 1, 0);
            Gl.glRotated(angleZ, 0, 0, 1);

            if (solution_ != null)
            {
                DisplaySpheres();
                DisplayConnections();
            }

            Gl.glPopMatrix();
            Gl.glFlush();
            AnT.Invalidate();
        }

        public void Display(object sender, EventArgs e)
        {
            Draw(0);
        }

        private void AnT_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyData)
            {
                case Keys.X:
                {
                    angleX += 10;
                    
                }
                break;

                case Keys.Y:
                {
                    angleY += 10;

                }
                break;

                case Keys.Z:
                {
                    angleZ += 10;

                }
                break;
            };

        }

        private void tabPage1_Click(object sender, EventArgs e)
        {

        }

        private void findSolutionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            solution_ = new int[data.dimension];

            int nchecked = 0;// = new int();

            for (int i = 0; i < groupBox2.Controls.Count; i++)
            {
                RadioButton rb = (RadioButton)groupBox2.Controls[i];
                if (rb.Checked == true)
                {
                    nchecked = i;
                    break;
                }
            }

            switch (nchecked)
            {
                case 0:
                    {
                        TSP.HillClimbing(data, solution_, new TSP.DrawDelagete(this.Draw), 0);
                        double hk = TSP.SolutionCoast(data, solution_);
                        toolStripLabel1.Text = "HC: " + hk.ToString();
                        break;
                    }
                case 1:
                    {
                        TSP.MutlistartHillClimbing(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
                        double mhk = TSP.SolutionCoast(data, solution_);
                        toolStripLabel1.Text = "HC(ms): " + mhk.ToString();
                        break;
                    }
                case 2:
                    {
                        TSP.Anneal(data, solution_, new TSP.DrawDelagete(this.Draw), 0);
                        double an = TSP.SolutionCoast(data, solution_);
                        toolStripLabel1.Text = "SA: " + an.ToString();
                        break;
                    }
                case 3:
                    {
                        TSP.MultiStartAnneling(data, solution_, 5, new TSP.DrawDelagete(this.Draw), 0);
                        double mst = TSP.SolutionCoast(data, solution_);
                        toolStripLabel1.Text = "SA(ms): " + mst.ToString();
                        break;
                    }
                case 4:
                    {

                        //     toolStripLabel1.Text = mst.ToString();
                        break;
                    }
                case 5:
                    {

                        //     toolStripLabel1.Text = mst.ToString();
                        break;
                    }
                default:
                    {
                        TSP.MutlistartHillClimbing(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
                        double mhk = TSP.SolutionCoast(data, solution_);
                        toolStripLabel1.Text = "HC(ms): " + mhk.ToString();
                        break;
                    }
            }

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        public void HillClimbingCallback()
        {
            solution_ = new int[data.dimension];
            TSP.HillClimbing(data, solution_, new TSP.DrawDelagete(this.Draw), 0);
            double length = TSP.SolutionCoast(data, solution_);
        }
        public void MultistartHillClimbingCallback()
        {
            solution_ = new int[data.dimension];
            TSP.MutlistartHillClimbing(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
            double length = TSP.SolutionCoast(data, solution_);
        }
        public void AnnealCallback()
        {
            solution_ = new int[data.dimension];
            TSP.Anneal(data, solution_, new TSP.DrawDelagete(this.Draw), 0);
            double length = TSP.SolutionCoast(data, solution_);
        }
        public void MultistartAnnealCallback()
        {
            solution_ = new int[data.dimension];
            TSP.MultiStartAnneling(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
            double length = TSP.SolutionCoast(data, solution_);
        }
        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            openFileDialog1.ShowDialog();
            if (openFileDialog1.CheckFileExists)
            {
                data = TSP.ReadFromFile(openFileDialog1.FileName);
            }


//            hillClimbingThread_.Start();
            multistartHillClimbingThread_.Start(); 
//            annealThread_.Start();
//            multistartAnnealThread_.Start();       
            //solution_ = new int[data.dimension];
            //Thread th = new Thread(new ThreadStart(this.dr));
            //th.Start();
            //TSP.HillClimbing(data, solution_, new TSP.DrawDelagete(this.Draw), 300);
            //double hk = TSP.SolutionCoast(data, solution_);
            //TSP.MutlistartHillClimbing(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
            //double mhk = TSP.SolutionCoast(data, solution_);
            //TSP.Anneal(data, solution_, new TSP.DrawDelagete(this.Draw), 0);
            //double an = TSP.SolutionCoast(data, solution_);
            //TSP.MultiStartAnneling(data, solution_, 100, new TSP.DrawDelagete(this.Draw), 0);
            //double mst = TSP.SolutionCoast(data, solution_);

        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            AnT_KeyDown(sender, e);
        }



    }
}
